/*
 * Copyright (c) 2011 Sapienza University of Rome.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the Sapienza University of Rome nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL SAPIENZA
 * UNIVERSITY OF ROME OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * @author Ugo Colesanti <colesanti@dis.uniroma1.it>
 * @version 1.01 (October 10, 2011)
 *
 */
#warning "********* DISSense Mode - NODE *************"

module NodeApplicationC{
  uses {
    // Interfaces for initialization:
    interface Boot;
    interface SplitControl as RadioControl;
    interface StdControl as ManagerControl ;

    interface Send;
    interface Receive ;

    interface Leds;

	interface Timer<TMilli> as Timer ;

	interface FlashLog ;

	interface Read<uint16_t> as ReadVoltage ;
	interface Read<uint16_t> as ReadSensor ;

	interface DISSenseSampling ;

  }

}

implementation {

	task void processRead() ;
	task void sendPacket() ;
	task void startApplication() ;

	uint16_t seqno ;
	app_data_t app_data_buf ;
	message_t app_msg_buf ;
	bool send_busy = FALSE ;

	event void Boot.booted(){
		seqno = 0 ;
		if (call RadioControl.start() != SUCCESS) {
			// do nothing
		}
	}

	event void RadioControl.startDone(error_t error){
		if (error != SUCCESS){
			return ; // do nothing
		}
		post startApplication() ;
	}

	task void startApplication(){
		dbg("Application","Application started\n") ;

		call ManagerControl.start() ;


		if (TOS_NODE_ID != 0){
#ifndef RELAYNODE
			call DISSenseSampling.setSamplingOffset(SAMPLING_OFFSET) ;

			//call LogWrite.erase() ;
#endif
		}
	}

	event void ReadVoltage.readDone(error_t result,uint16_t value){
		if(result == SUCCESS){
				app_data_buf.voltage = value ;
		}
		else{
			app_data_buf.voltage = 0xffff ;
		}

		call ReadSensor.read() ;
	}

	event void ReadSensor.readDone(error_t result,uint16_t value){
		uint8_t readings_count ;
		if(result == SUCCESS){
			atomic{
				for(readings_count = 0; readings_count < SENSOR_COUNT; readings_count++){
					app_data_buf.sensor[readings_count].data = readings_count +1 ;
					app_data_buf.sensor[readings_count].temp = (readings_count+1) * 11;
				}
			}

		}
		else{
			atomic{
				for(readings_count = 0; readings_count < SENSOR_COUNT; readings_count++){
					app_data_buf.sensor[readings_count].data = 0xffff ;
					app_data_buf.sensor[readings_count].temp = 0xffff ;
				}
			}
		}

		call FlashLog.log(&app_data_buf,sizeof(app_data_buf)) ;
	}


	event void Timer.fired(){

	}


	event void RadioControl.stopDone(error_t error){}


	task void processRead(){
		// call a read to all the peripherals and wait to have the value back

		atomic{
			app_data_buf.seqno = seqno ;
			app_data_buf.timestamp = call Timer.getNow() ;
		}
		call ReadVoltage.read() ;
	  }

	  event void FlashLog.logDone(void* msg, error_t result){
		  post sendPacket() ;
	  }


	  task void sendPacket(){
		  if(!send_busy){
			  uint8_t datareadings ;
			  atomic{
				  app_data_t* app_data = (app_data_t *) call Send.getPayload(&app_msg_buf, sizeof(app_data_t));
				  if(app_data != NULL){

					  app_data->seqno = app_data_buf.seqno ;
					  app_data->voltage = app_data_buf.voltage ;
					  app_data->timestamp = app_data_buf.timestamp ;
					  for(datareadings = 0; datareadings < SENSOR_COUNT; datareadings++){
						  app_data->sensor[datareadings].data = app_data_buf.sensor[datareadings].data ;
						  app_data->sensor[datareadings].temp = app_data_buf.sensor[datareadings].temp ;
					  }

					  if (call Send.send(&app_msg_buf, sizeof(app_data_t)) == SUCCESS){
						  send_busy = TRUE ;
					  }
					  else post sendPacket() ;

				  }
			  }
		  }
	 }

	  event void Send.sendDone(message_t* msg, error_t error) {
		  atomic{
			  send_busy = FALSE ;
			  seqno++ ;
		  }
	  }

	  event message_t* Receive.receive(message_t* msg, void *payload, uint8_t len) {return msg;} // Should be removed

	  event void DISSenseSampling.startSampling() {
		  post processRead() ;
	  }
}
